//
//  SPErrorReporter.m
//  SPKit
//
//  Created by LSP on 16/2/23.
//  Copyright © 2016年 SP. All rights reserved.
//
//#import <arpa/inet.h>
//#import <ifaddrs.h>
//#import <netdb.h>
//#import <sys/socket.h>
//
//#import <CoreFoundation/CoreFoundation.h>


#import "SPErrorReporter.h"
#import <SystemConfiguration/SystemConfiguration.h>
//#import <netinet/in.h>

@interface SPErrorReporter()
//@property (nonatomic, copy) ReportErrorAction reportAction;
-(void)networkChanged;
@end

static void NetworkChangedCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info){
    #pragma unused (target, flags)
    NSCAssert(info != NULL, @"info was NULL in ReachabilityCallback");
    NSCAssert([(__bridge NSObject*) info isKindOfClass: [SPErrorReporter class]], @"info was wrong class in ReachabilityCallback");
    
    SPErrorReporter* noteObject = (__bridge SPErrorReporter *)info;
    [noteObject networkChanged];
}

#pragma mark - Class SPErrorReporter
@implementation SPErrorReporter{
    NSString *_storePath;
    BOOL _connected;
    NSMutableArray *_allErrors;
    NSMutableArray *_errors;
    ReportErrorHttpRequest _reportAction;
    
	SCNetworkReachabilityRef _reachabilityRef;
}

- (instancetype)init
{
    self = [super init];
    if (self) {
        SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, [@"www.baidu.com" UTF8String]);
        if (reachability != NULL) {
            _reachabilityRef = reachability;

            SCNetworkReachabilityContext context = {0, (__bridge void *)(self), NULL, NULL, NULL};

            if (SCNetworkReachabilitySetCallback(_reachabilityRef, NetworkChangedCallback, &context)) {
                SCNetworkReachabilityScheduleWithRunLoop(_reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
            }
            _connected = NO;
        }else{
            _connected = YES;
        }
    }
    return self;
}

-(void)reportError:(SPError *)error{
    [_allErrors addObject:error];
    [_errors addObject:error];
}

-(void)startReport{
    NSArray *arr = [NSArray arrayWithContentsOfFile:self.storePath];
    _errors = [NSMutableArray array];
    _allErrors = [NSMutableArray array];
    if (arr) {
        for (NSDictionary *dic in arr) {
            if (!dic.count) {
                continue;
            }
            SPError *er = [SPError modelFromDic:dic];
            [_allErrors addObject:er];
            [_errors addObject:er];
        }
    }
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(reportCircle) object:nil];
    thread.name = @"ErrorReportCircle";
    [thread start];
}

-(void)reportCircle{
    __weak SPErrorReporter *wself = self;
    while (YES) {
        if (_connected && _errors.count) {
            SPError *err = _errors.firstObject;
            [_errors removeObjectAtIndex:0];
            NSLog(@"StartReportError:%@", err);
            _reportAction(err, ^(BOOL result, SPError *error){
                NSAssert(error != nil, @"^(BOOL result, SPError *error) error不可为空。");
                dispatch_async(dispatch_get_global_queue(0, 0), ^{
                    if (result) {
                        [wself reportSuccess:error];
                    }else{
                        [wself reportFail:error];
                    }
                });
            });
            [NSThread sleepForTimeInterval:0.5];
        }else{
            [NSThread sleepForTimeInterval:5];
        }
    }
}
-(void)reportSuccess:(SPError *)err{
    [_allErrors removeObject:err];
    NSLog(@"ReportFail:ErrorID=%lld", err.recordID);
}
-(void)reportFail:(SPError *)err{
    [_errors addObject:err];
    NSLog(@"ReportSuccess:ErrorID=%lld", err.recordID);
}

-(void)saveToDisk{
    NSMutableArray *arr = [NSMutableArray array];
    for (SPError *error in _allErrors) {
        [arr addObject:error.dictionary];
    }
    [arr writeToFile:self.storePath atomically:YES];
}
-(void)networkChanged{
    int returnValue = 0;
    SCNetworkReachabilityFlags flags;
    
    if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags))
    {
        returnValue = [self networkStatusForFlags:flags];
    }
    _connected = returnValue;
}
- (int)networkStatusForFlags:(SCNetworkReachabilityFlags)flags
{
    if ((flags & kSCNetworkReachabilityFlagsReachable) == 0)
    {
        return 0;
    }
    
    int returnValue = 0;
    
    if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0) {
        returnValue = 1;
    }
    if ((((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) ||
         (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0)) {
        if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0) {
            returnValue = 1;
        }
    }
    if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN) {
        returnValue = 2;
    }
    
    return returnValue;
}

#pragma mark Getter&Setter
-(void)setReportAction:(ReportErrorHttpRequest)reportAction{
    _reportAction = [reportAction copy];
}
-(NSString *)storePath{
    if (!_storePath) {
        _storePath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject;
        _storePath = [_storePath stringByAppendingPathComponent:@"SPErrors"];
    }
    return _storePath;
}

-(NSArray *)allErrors{
    return [NSArray arrayWithArray:_allErrors];
}
-(void)dealloc{
    if (_reachabilityRef != NULL)
    {
        SCNetworkReachabilityUnscheduleFromRunLoop(_reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
        CFRelease(_reachabilityRef);
    }
}
@end





#ifndef __NotNull_h__
NSString *notNull(NSString *str){
    if (!str || [str isKindOfClass:[NSNull class]]) {
        return @"";
    }
    return str;
}
#endif


#pragma mark - Class SPError
@implementation SPError

- (instancetype)initWithDic:(NSDictionary *)dic
{
//#ifdef __ModelBase_h__
    self = [super initWithDic:dic];
    if (self) {
//#else
//    self = [super init];
//    if (self) {
//        _dictionary = dic;
//#endif
        _errorType = [dic[@"errorCode"] longLongValue];
        _internalCode = [dic[@"internalCode"] longLongValue];
        _creatTime = [dic[@"creatTime"] doubleValue];
        _userID = dic[@"userID"];
        if (!_userID) {
            _userID = @"0";
        }
        _message = dic[@"message"];
        if (!_message) {
            _message = @"iOS系统内部错误导致消息构造失败！";
        }
        _appVersion = dic[@"appVersion"];
        if (!_appVersion) {
            _appVersion = @"version.error";
        }
        NSNumber *recordID = dic[@"recordID"];
        if (recordID) {
            _recordID = recordID.integerValue;
        }else{
            NSInteger ID = [[NSUserDefaults standardUserDefaults] integerForKey:@"SPErrorRecordID"];
            self.recordID = ID++;
            [[NSUserDefaults standardUserDefaults] setInteger:ID forKey:@"SPErrorRecordID"];
        }
    }
    return self;
}
    
+ (instancetype)errorWithType:(int64_t)type userID:(NSString *)uid message:(NSString *)msg appVersion:(NSString *)version internalCode:(int64_t)internal {
    return [[self alloc] initWithType:type userID:uid message:msg appVersion:version internalCode:internal];
}

//#ifndef __ModelBase_h__
//+(instancetype)modelFromDic:(NSDictionary *)dic{
//    return [[self alloc]initWithDic:dic];
//}
//+(NSArray *)modelsFromDicArray:(NSArray *)array{
//    NSMutableArray *models = [NSMutableArray array];
//
//    for (NSDictionary *dic in array) {
//        [models addObject:[self modelFromDic:dic]];
//    }
//    return [NSArray arrayWithArray:models];
//}
//#endif

-(instancetype)initWithType:(int64_t)type userID:(NSString *)uid message:(NSString *)msg appVersion:(NSString *)version internalCode:(int64_t)internal
{
    static NSInteger ID = 0;
    if (!ID) {
        ID = [[NSUserDefaults standardUserDefaults] integerForKey:@"SPErrorRecordID"];
    }
    if (!uid) {
        uid = @"0";
    }
    if (!msg) {
        msg = @"无错误信息";
    }
    if (!version) {
        version = @"version.error";
    }
    [[NSUserDefaults standardUserDefaults] setInteger:++ID forKey:@"SPErrorRecordID"];
    
    msg = [NSString stringWithFormat:@"RecordID:%-4lld###iOS internal Error Code:%-6lld###appVersion:%@###%@", (long long)ID, internal, version, msg];
    NSDictionary *dic = @{  @"errorCode": @(type),
                            @"internalCode": @(internal),
                            @"creatTime": @([[NSDate date] timeIntervalSince1970]),
                            @"appVersion": notNull(version),
                            @"message": notNull(msg),
                            @"userID": uid,
                            @"recordID":@(ID)
                            };
    return [self initWithDic:dic];
}

#if DEBUG
-(NSString *)description{
    NSError *error;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:self options:0 error:&error];
    
    if (!jsonData) {
        //LSP// NSLog(@"toJsonString error: %@", error);
        return @"";
    }
    
    return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
}
#endif


@end
